#ifndef __M_BINDING_H__
#define __M_BINDING_H__
#include "../MQcommon/helper.hpp"
#include "../MQcommon/mq_msg.pb.h"
#include"../MQcommon/logger.hpp"

#include <google/protobuf/map.h>
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>

namespace bitmq{
    struct Binding{
    using ptr=std::shared_ptr<Binding>;
    //交换机名称
    std::string exchange_name;
    //队列名称
    std::string queue_name;
    //绑定的key信息
    std::string binding_key;

    Binding() {}
    Binding(const std::string &ename, const std::string &qname, const std::string &key) : exchange_name(ename), queue_name(qname), binding_key(key) {}
    };//为什么没有可持久化标志呢？绑定信息固然重要，但它的持久化取决于队列和交换机是否持久化，两个当中的一个不持久化，那么绑定信息持久化就是没有意义的
    using MsgQueueBindingMap=std::unordered_map<std::string,Binding::ptr>;
    using BindingMap=std::unordered_map<std::string,MsgQueueBindingMap>;
    class BindingMapper{
    public:
    BindingMapper(const std::string &dbfile):sql_helper(dbfile){
        std::string path = FileHelper::parentDirectory(dbfile);
        FileHelper::createDirectory(path);
        sql_helper.open();
        createTable();
    }
    void createTable(){
        #define CREATE_TABLE "create table if not exists binding_table(\
        exchange_name varchar(32),\
        queue_name varchar(32),\
        binding_key varchar(32));"
        bool ret=sql_helper.exec(CREATE_TABLE,nullptr,nullptr);
        if(ret != true ){
            ELOG("创建表[%s]失败","binding_table");
            abort();
        }
    }
    void removeTable(){
        #define DROP_TABLE "drop table if exists binding_table"
        bool ret=sql_helper.exec(DROP_TABLE,nullptr,nullptr);
        if(ret != true){
            ELOG("删除表[%s]失败","binding_table");
        }
    }
    bool insert(Binding::ptr &binding){
        std::stringstream sql;
        sql << "insert into binding_table values(";
        sql << "'" << binding->exchange_name << "', ";
        sql << "'" << binding->queue_name << "', ";
        sql << "'" << binding->binding_key << "');";
        return sql_helper.exec(sql.str(), nullptr, nullptr);
    }
    void remove(const std::string &ename, const std::string &qname){
        std::stringstream sql;
        sql << "delete from binding_table where ";
        sql << "exchange_name='" << ename << "' and ";
        sql << "msgqueue_name='" << qname << "';";
        sql_helper.exec(sql.str(), nullptr, nullptr);
    }
    void removeExchangeBindings(const std::string &ename){
        std::stringstream sql;
        sql << "delete from binding_table where ";
        sql << "exchange_name='" << ename<<"';";
        sql_helper.exec(sql.str(), nullptr, nullptr);
    }
    void removeMsgQueueBindings(const std::string &qname){
        std::stringstream sql;
        sql << "delete from binding_table where ";
        sql << "exchange_name='" << qname <<"';";
        sql_helper.exec(sql.str(), nullptr, nullptr);
    }
    BindingMap recovery(){
        BindingMap result;
        std::string sql = "select exchange_name, queue_name, binding_key from binding_table;";
        sql_helper.exec(sql, selectCallBack, &result);
        return result;
    }
    private:
    //using MsgQueueBindingMap=std::unordered_map<std::string,Binding::ptr>;
    //using BindingMap=std::unordered_map<std::string,MsgQueueBindingMap>;
    static int selectCallBack(void* args,int count,char** row,char**  fileds){
        BindingMap* result=(BindingMap*)args;
        auto it=std::make_shared<Binding>();
        it->exchange_name=row[0];
        it->queue_name=row[1];
        it->binding_key=row[2];
        auto& queue_binding_map=(*result)[it->exchange_name];//如果当前没有，则直接构造，如果有，直接使用
        queue_binding_map.insert(std::make_pair(it->queue_name,it));//一个交换机，对应队列和绑定信息的map，这个map当中有很多这个交换机和不同队列的绑定信息
        return 0;
    }//从表中得到的数据:交换机名称 队列名称 绑定信息
    Sqlite3Helper sql_helper;
    };
    
    class BindingManager{
    public:
        using ptr=std::shared_ptr<BindingManager>;
        BindingManager(const std::string& dbfile):_helper(dbfile){
            _binding_map=_helper.recovery();
        }
        bool bind(const std::string &ename, const std::string &qname, const std::string &key, bool durable){
            std::unique_lock<std::mutex> lock(_mutex);
            Binding::ptr value=std::make_shared<Binding>();
            value->exchange_name = ename;
            value->queue_name = qname;
            value->binding_key = key;
            auto it = _binding_map.find(ename);
            if(it != _binding_map.end()){
                auto next_it = _binding_map[ename].find(qname);
                if(next_it != _binding_map[ename].end()){
                    DLOG("该绑定信息已经存在，不用重复添加");
                    return false;
                }
            }
            if(durable == true){
                _helper.insert(value);
            }
            auto& queue_binding_map=_binding_map[value->exchange_name];//如果当前没有，则直接构造，如果有，直接使用
            queue_binding_map.insert(std::make_pair(qname,value));
            
        }
        void unBind(const std::string &ename, const std::string &qname){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _binding_map.find(ename);
            if (it == _binding_map.end()){
                DLOG("该绑定信息不存在，不用解绑");
                return;
            }
            auto next_it = _binding_map[ename].find(qname);
            if (next_it == _binding_map[ename].end()){
                DLOG("该绑定信息不存在，不用解绑");
                return;
            }
            _helper.remove(ename,qname);
            _binding_map[ename].erase(qname);
        }
        void removeExchangeBindings(const std::string &ename){
            std::unique_lock<std::mutex> lock(_mutex);
            _helper.removeExchangeBindings(ename);
            _binding_map.erase(ename);
        }
        void removeMsgQueueBindings(const std::string &qname){
            std::unique_lock<std::mutex> lock(_mutex);
            _helper.removeMsgQueueBindings(qname);
            for (auto start = _binding_map.begin(); start != _binding_map.end(); ++start)
            {
                // 遍历每个交换机的绑定信息，从中移除指定队列的相关信息
                start->second.erase(qname);
            }
        }
        MsgQueueBindingMap getExchangeBindings(const std::string &ename){
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _binding_map.find(ename);
            if (eit == _binding_map.end()) { 
                return MsgQueueBindingMap(); 
            }
            return eit->second;
        }
        Binding::ptr getBinding(const std::string &ename, const std::string &qname){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _binding_map.find(ename);
            if (it == _binding_map.end()){
                DLOG("该绑定信息不存在");
                return nullptr;
            }
            auto next_it = _binding_map[ename].find(qname);
            if (next_it == _binding_map[ename].end()){
                DLOG("该绑定信息不存在");
                return nullptr;
            }
            return _binding_map[ename][qname];
        }
        bool exists(const std::string &ename, const std::string &qname){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _binding_map.find(ename);
            if (it == _binding_map.end())
            {
                return false;
            }
            auto next_it = (it->second).find(qname);
            if (next_it == it->second.end())
            {
                return false;
            }
            return true;
        }
        size_t size(){
            size_t total_size = 0;
            std::unique_lock<std::mutex> lock(_mutex);
            for (auto start = _binding_map.begin(); start != _binding_map.end(); ++start)
            {
                // 遍历每个交换机的绑定信息，从中移除指定队列的相关信息
                total_size += start->second.size();
            }
            return total_size;
        }
        void clear(){
            _helper.removeTable();
            _binding_map.clear();
        }
    private:
        std::mutex _mutex;
        BindingMapper _helper;
        BindingMap _binding_map;
    };
} // namespace bitm
#endif